package Generic;

import gui.JOptionPaneMultiInput2;

import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;

@SuppressWarnings({"serial","rawtypes"})
public class EAApplicationFrame extends ApplicationFrame{

	private int populationSize;
	private int numberOfGenerations;
	private double crossoverRate;
	private double mutationRate;
	private Class eaClass;

	final static int NUMBER_OF_GENERATIONS_TICKS_GRAPH = 20;

	public EAApplicationFrame(String title, Class eaClass) {
		super(title);
		populationSize = EvolutionaryAlgorithm.DEFAULT_POPULATION_SIZE;
		numberOfGenerations = (int) EvolutionaryAlgorithm.DEFAULT_NUMBER_OF_GENERATIONS;
		crossoverRate = EvolutionaryAlgorithm.DEFAULT_CROSSOVER_RATE;
		mutationRate = EvolutionaryAlgorithm.DEFAULT_MUTATION_RATE;
		this.eaClass = eaClass;
	}

	public static void runEvolution(Class eaClass) {
		EAApplicationFrame applicationFrame = new EAApplicationFrame("Evolution",eaClass);

		JFrame frame = new JFrame();
		while(true){
			applicationFrame.runEvolutionAndPlayGod(eaClass);

			int answer = JOptionPane.showConfirmDialog(frame, 
					"Would you like to run again?", "Info", JOptionPane.YES_NO_OPTION);

			if (answer == JOptionPane.NO_OPTION || answer == JOptionPane.CLOSED_OPTION) System.exit(0); 
		}
	}

	private void runEvolutionAndPlayGod(Class eaClass) {

		List<String> parameters = new ArrayList<String>();
		List<Double> defaults = new ArrayList<Double>();

		parameters.add("Population Size");
		defaults.add((double) populationSize);
		parameters.add("Number of Generations");
		defaults.add((double) numberOfGenerations);
		parameters.add("Crossover Rate");
		defaults.add(crossoverRate);
		parameters.add("Mutation Rate");
		defaults.add(mutationRate);

		parameters.addAll(EvolutionaryAlgorithm.additionalParameters);
		defaults.addAll(EvolutionaryAlgorithm.additionalParameterValues);

		JOptionPaneMultiInput2 multiInput = new JOptionPaneMultiInput2(parameters,defaults);

		populationSize = (int) multiInput.getParameterValue(0);
		numberOfGenerations = (int) multiInput.getParameterValue(1);
		crossoverRate = multiInput.getParameterValue(2);
		mutationRate = multiInput.getParameterValue(3);

		for(int i = 0; i<EvolutionaryAlgorithm.additionalParameterValues.size();i++)
		{
			EvolutionaryAlgorithm.additionalParameterValues.set(i, multiInput.getParameterValue(i+4));
		}
		
		EvolutionaryAlgorithm ea = null;

		try {
			ea = (EvolutionaryAlgorithm) eaClass.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		ea.initialize(populationSize, crossoverRate, mutationRate);
		
		runEA(ea);
	}

	public void runEA(EvolutionaryAlgorithm ea){

		final XYSeries maxSeries = new XYSeries("Max Fitness");         
		final XYSeries averageSeries = new XYSeries("Average Fitness");
		final XYSeries standardDeviationSeries = new XYSeries("Standard Deviation");
		final XYSeriesCollection standardCollection = new XYSeriesCollection();
		standardCollection.addSeries(maxSeries);
		standardCollection.addSeries(averageSeries);
		standardCollection.addSeries(standardDeviationSeries);
		
		final NumberAxis standardAxis = new NumberAxis("Fitness");
		final XYPlot standardSubplot = new XYPlot(standardCollection, null, standardAxis,new StandardXYItemRenderer());
		
		List<XYPlot> additionalPlots = new ArrayList<XYPlot>();
		for(String string : EvolutionaryAlgorithm.additionalStatisticNames)
		{
			XYSeries series = new XYSeries(string);
			XYSeriesCollection collection = new XYSeriesCollection();
			collection.addSeries(series);
			NumberAxis axis = new NumberAxis(string);
			StandardXYItemRenderer rend = new StandardXYItemRenderer();
			rend.setSeriesPaint(0, Color.BLACK);
			XYPlot subplot = new XYPlot(collection, null, axis,rend);
			additionalPlots.add(subplot);
		}
		
		final CombinedDomainXYPlot plot = new CombinedDomainXYPlot(new NumberAxis("Generations"));
		plot.add(standardSubplot,1);
		for(XYPlot subplot : additionalPlots)plot.add(subplot);
		
		final JFreeChart chart = new JFreeChart(eaClass.getName(),JFreeChart.DEFAULT_TITLE_FONT,plot,true);
		
		final ChartPanel chartPanel = new ChartPanel(chart);
		chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
		setContentPane(chartPanel);
		pack();
		setVisible(true);

		for(int i = 0; i < numberOfGenerations; i++)
		{
			ea.iterateGeneration();

			maxSeries.add(i, ea.getMaxFitness());
			averageSeries.add(i, ea.getAverageFitness());
			standardDeviationSeries.add(i,ea.getStandardDeviation());
			for(XYPlot subplot : additionalPlots){
				XYSeries series = ((XYSeriesCollection)subplot.getDataset()).getSeries(0);
				series.add(i,ea.getAdditionalStatistic(series.getKey().toString()));
			}
		}
		try 
		{
			ChartUtilities.saveChartAsJPEG(new File(eaClass.getName()+"_pop"+populationSize+"_cross"+crossoverRate+"_mut"+mutationRate+".jpg"), chart, this.getWidth(), this.getHeight());
		} catch (IOException e) 
		{
			e.printStackTrace();
		}
	}
}
